package trading.util;

import java.util.ArrayList;
import java.util.List;

import trading.algo.BearTask.VIXFuturePriceTask;
import trading.bo.DBAccessorBO;
import trading.util.IBMsgIDGen.IBMsgBean;
import trading.util.IBMsgIDGen.IBMsgType;

import com.ib.client.Contract;
import com.ib.client.ContractDetails;
import com.ib.client.EClientSocket;
import com.ib.client.EWrapper;
import com.ib.client.Execution;
import com.ib.client.Order;
import com.ib.client.OrderState;
import com.ib.client.UnderComp;

public class IBAPI implements EWrapper {
	
    private IBMsgIDGen ibMsgIDGen;
    
    public void setIbMsgIDGen(IBMsgIDGen ibMsgIDGen) {
        this.ibMsgIDGen = ibMsgIDGen;
    }
    
    private DBAccessorBO dbAccessorBO;
    
    public void setDbAccessorBO(DBAccessorBO dbAccessorBO) {
    	this.dbAccessorBO = dbAccessorBO;
    }
	
	private EClientSocket m_client = new EClientSocket( this);
	
	public EClientSocket getClient() {
		return this.m_client;
	}
	
	@Override
	public void error(Exception e) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void error(String str) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void error(int id, int errorCode, String errorMsg) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void connectionClosed() {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void tickPrice(int tickerId, int field, double price,
			int canAutoExecute) {
		IBMsgBean msgBean = ibMsgIDGen.getCurrentMsgBean();
		if (msgBean != null) {
			if (msgBean.getMsgType() == IBMsgType.CURRENT_FUTURE_PRICE) {
				if (field == Constants.IB.TICK_PRICE_LAST) {
			    	System.out.println("Most recent VIX future price is : " + price);
			    	if (VIXFrontMonthCheckUtil.isTryingToGetFrontMonthDate()) {
				    	VIXFrontMonthCheckUtil.setVIXFrontMonthPrice(price + "");
			    	} else {
			    		List<Double> VIXFuturePriceList = new ArrayList<Double>();
			    		double dummyNumber = 20;
			    		VIXFuturePriceList.add(dummyNumber);
			    		VIXFuturePriceList.add(price);
			    		this.dbAccessorBO.updateVIXFuturePrice(VIXFuturePriceList);
			    	}
			    	this.m_client.cancelMktData(tickerId);
			    	ibMsgIDGen.releaseCurrentMsgBean();
            	}
			} else if (msgBean.getMsgType() == IBMsgType.CURRENT_OPTION_PRICE) {
				if (field == Constants.IB.TICK_PRICE_LAST) {
					OptionSpotPriceUtil.setPrice(price);
					this.m_client.cancelMktData(tickerId);
					ibMsgIDGen.releaseCurrentMsgBean();
				}
			}
		}
	}

	@Override
	public void tickSize(int tickerId, int field, int size) {
		// TODO Auto-generated method stub
	}

	@Override
	public void tickOptionComputation(int tickerId, int field,
			double impliedVol, double delta, double optPrice,
			double pvDividend, double gamma, double vega, double theta,
			double undPrice) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void tickGeneric(int tickerId, int tickType, double value) {
	}

	@Override
	public void tickString(int tickerId, int tickType, String value) {
		// TODO Auto-generated method stub
	}

	@Override
	public void tickEFP(int tickerId, int tickType, double basisPoints,
			String formattedBasisPoints, double impliedFuture, int holdDays,
			String futureExpiry, double dividendImpact, double dividendsToExpiry) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void orderStatus(int orderId, String status, int filled,
			int remaining, double avgFillPrice, int permId, int parentId,
			double lastFillPrice, int clientId, String whyHeld) {
		if (!status.equals("Submitted") && !status.equals("PreSubmitted")) {
			dbAccessorBO.removeOpenOrder(permId);
		}
	}

	@Override
	public void openOrder(int orderId, Contract contract, Order order,
			OrderState orderState) {
		dbAccessorBO.updateOpenOrder(orderId, contract.m_localSymbol, contract.m_secType, order.m_orderType, order.m_totalQuantity, order.m_permId, order.m_lmtPrice, order.m_action, order.m_auxPrice);
	}

	@Override
	public void openOrderEnd() {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void updateAccountValue(String key, String value, String currency,
			String accountName) {
		if (key.equals("AvailableFunds")) {
			this.dbAccessorBO.updateAvailableFunds(value);
		} else if (key.equals("NetLiquidation")) {
			this.dbAccessorBO.updateNetLiquidation(value);
		} else if (key.equals("TotalCashBalance")) {
			this.dbAccessorBO.updateTotalCashBalance(value);
		} else if (key.equals("AccountCode")) {
		    this.dbAccessorBO.updateAccountId(value);
		}
	}

	@Override
	public void updatePortfolio(Contract contract, int position,
			double marketPrice, double marketValue, double averageCost,
			double unrealizedPNL, double realizedPNL, String accountName) {
        if (contract.m_secType.equals("STK")) {
        	this.dbAccessorBO.updatePortfolioStockPositions(contract, position);
        } else if (contract.m_secType.equals("OPT")) {
        	this.dbAccessorBO.updatePortfolioOptionPositions(contract, position);
        }
	}

	@Override
	public void updateAccountTime(String timeStamp) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void accountDownloadEnd(String accountName) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void nextValidId(int orderId) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void contractDetails(int reqId, ContractDetails contractDetails) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void bondContractDetails(int reqId, ContractDetails contractDetails) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void contractDetailsEnd(int reqId) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void execDetails(int reqId, Contract contract, Execution execution) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void execDetailsEnd(int reqId) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void updateMktDepth(int tickerId, int position, int operation,
			int side, double price, int size) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void updateMktDepthL2(int tickerId, int position,
			String marketMaker, int operation, int side, double price, int size) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void updateNewsBulletin(int msgId, int msgType, String message,
			String origExchange) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void managedAccounts(String accountsList) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void receiveFA(int faDataType, String xml) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void historicalData(int reqId, String date, double open,
			double high, double low, double close, int volume, int count,
			double WAP, boolean hasGaps) {
		IBMsgBean msgBean = ibMsgIDGen.getCurrentMsgBean();
        if (date.startsWith("finished")) {
        	if (msgBean.getMsgType() == IBMsgType.HISTORICAL_LOW_PRICE_DATE) {
        		dbAccessorBO.updateHistoricalLowPriceAndDate(msgBean, 
            			msgBean.getOtherInfo().get(Constants.HISTORICAL_LOW_PRICE), 
            			msgBean.getOtherInfo().get(Constants.HISTORICAL_LOW_DATE));
        	} else if (msgBean.getMsgType() == IBMsgType.MARKET_STATUS) {
        		if (msgBean.getOtherInfo().get(Constants.MARKET_STATUS) != null) {
        			dbAccessorBO.updateMarketSentiment(msgBean.getOtherInfo().get(Constants.MARKET_STATUS));
        		} else {
        			dbAccessorBO.updateMarketSentiment(Constants.BULL);
        		}
        	}
        	this.m_client.cancelHistoricalData(msgBean.getId());
        	ibMsgIDGen.releaseCurrentMsgBean();
        } else if (msgBean != null) {
        	if (msgBean.getMsgType() == IBMsgType.LAST_CLOSE_PRICE) {
        		if (close > 0) {
        	        // store close price in db
        	        dbAccessorBO.updateMonitoredStockTickersLastPrice(msgBean, close);
        		}
        	} else if(msgBean.getMsgType() == IBMsgType.LAST_CLOSE_FUTURE_PRICE) {
        		if (close > 0){
    				System.out.println("Last close VIX future price is : " + close);
        			if (VIXFrontMonthCheckUtil.isTryingToGetFrontMonthDate()) {
        				VIXFrontMonthCheckUtil.setVIXFrontMonthPrice(close + "");
        			} else {
        				VIXFuturePriceTask.storeVIXFuturePrice(close);
        				List<Double> VIXFuturePriceList = VIXFuturePriceTask.getVIXFuturePriceList();
        				if (VIXFuturePriceList.size() == 2) {
        					this.dbAccessorBO.updateVIXFuturePrice(VIXFuturePriceList);
        					VIXFuturePriceTask.resetVIXFuturePriceList();
        				}
        			}
        		}
        		
        	} else if (msgBean.getMsgType() == IBMsgType.HISTORICAL_LOW_PRICE_DATE) {
        	
        		if (msgBean.getOtherInfo().get(Constants.HISTORICAL_LOW_PRICE) == null) {
        			msgBean.getOtherInfo().put(Constants.HISTORICAL_LOW_PRICE, low + "");
        			msgBean.getOtherInfo().put(Constants.HISTORICAL_LOW_DATE, date);
        		} else {
        			if (low < Double.parseDouble(msgBean.getOtherInfo().get(Constants.HISTORICAL_LOW_PRICE))) {
            			msgBean.getOtherInfo().put(Constants.HISTORICAL_LOW_PRICE, low + "");
            			msgBean.getOtherInfo().put(Constants.HISTORICAL_LOW_DATE, date);
        			}
        		}
        	} else if (msgBean.getMsgType() == IBMsgType.MARKET_STATUS) {
    			double historicalLow = Double.parseDouble(msgBean.getOtherInfo().get(Constants.HISTORICAL_LOW_PRICE));
        		if (msgBean.getOtherInfo().get("afterHistoricalLowData") == null ||
        				!msgBean.getOtherInfo().get("afterHistoricalLowData").equals("true")) {
        			if (low == historicalLow) {
        				msgBean.getOtherInfo().put("afterHistoricalLowData", "true");
        			}
        		} else {
        			if (100 * (high - historicalLow) > historicalLow * Constants.Algo.BULL_TO_BEAR_PERCENT_CHANGE_CRITERIA) {
        				msgBean.getOtherInfo().put(Constants.MARKET_STATUS, Constants.BEAR);
        			}
        		}
        			
        	}
        }
	}

	@Override
	public void scannerParameters(String xml) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void scannerData(int reqId, int rank,
			ContractDetails contractDetails, String distance, String benchmark,
			String projection, String legsStr) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void scannerDataEnd(int reqId) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void realtimeBar(int reqId, long time, double open, double high,
			double low, double close, long volume, double wap, int count) {
		IBMsgBean msgBean = ibMsgIDGen.getMsgBean(reqId);
		if (msgBean.getMsgType() == IBMsgType.LATEST_PRICE) {
			if (close > 0) {
				this.dbAccessorBO.updateMonitoredStockTickersLastPrice(msgBean, close);
			}
		}
	}

	@Override
	public void currentTime(long time) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void fundamentalData(int reqId, String data) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void deltaNeutralValidation(int reqId, UnderComp underComp) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void tickSnapshotEnd(int reqId) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void marketDataType(int reqId, int marketDataType) {
		// TODO Auto-generated method stub
		
	}

}
